﻿#region Using

using System.Threading;

#endregion

namespace WSMon.Engine.Threading
{
    /// <summary>
    /// Pretty simple Thread Pool implementation
    /// http://ferruh.mavituna.com/net-multithreading-ve-basit-bir-threadpool-implementasyonu-oku/
    /// </summary>
    /// <remarks></remarks>
    public class ThreadPooler
    {
        #region "Properties"

        private readonly object _countLock = new object();
        private readonly object _pushLock = new object();
        private bool _allPushed;
        private int _count;

        /// <summary>
        /// New Thread Pool
        /// </summary>
        /// <param name="maxThreadCount"></param>
        /// <remarks></remarks>
        public ThreadPooler(int maxThreadCount)
        {
            MaxThreadCount = maxThreadCount;
        }

        /// <summary>
        /// Current Thread Count 
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public int ThreadCount
        {
            get
            {
                lock (_countLock)
                {
                    return _count;
                }
            }
        }

        /// <summary>
        /// Maximum Thread Count
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public int MaxThreadCount { get; set; }

        /// <summary>
        /// Is job finished (all threads closed?)
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks><c>True</c> if all opened threads closed <c>False</c> otherwise</remarks>
        public bool Finished
        {
            get { return AllPushed && ThreadCount == 0; }
        }

        /// <summary>
        /// Thread Status
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public ThreadStatus Status { get; set; }

        /// <summary>
        /// All jobs are pushed to ThreadPool
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        private bool AllPushed
        {
            get
            {
                lock (_pushLock)
                {
                    return _allPushed;
                }
            }
        }

        #endregion

        #region "Enums"

        /// <summary>
        /// Current status of thread pool
        /// </summary>
        /// <remarks></remarks>
        public enum ThreadStatus
        {
            Started,
            Stopped,
            Paused
        }

        #endregion

        #region "Events"

        #region Delegates

        public delegate void ThreadsFinishedEventHandler();

        #endregion

        /// <summary>
        /// Inform that there is no more thread in the pool
        /// </summary>
        /// <remarks></remarks>
        public event ThreadsFinishedEventHandler ThreadsFinished;

        #endregion

        #region "Thread Management"

        /// <summary>
        /// Open a new thread
        /// </summary>
        public void Open()
        {
            Interlocked.Increment(ref _count);
        }

        /// <summary>
        /// Informs Thread Pool that all jobs pushed
        /// </summary>
        /// <remarks></remarks>
        public void AllJobsPushed()
        {
            lock (_pushLock)
            {
                _allPushed = true;
            }
        }

        /// <summary>
        /// Close one thread
        /// </summary>
        public void Close()
        {
            Interlocked.Decrement(ref _count);

            if (Finished)
                if (ThreadsFinished != null)
                {
                    ThreadsFinished();
                }
        }

        /// <summary>
        /// Wait for opened threads before open new ones
        /// </summary>
        /// <remarks></remarks>
        public void WaitForThreads()
        {
            while ((ThreadCount >= MaxThreadCount) || (Status == ThreadStatus.Paused))
            {
                Thread.Sleep(20);
            }
        }

        #endregion
    }
}